/**
//文档生成日期：2005.10.07
//
//(1)概述：
//类名称：RssFeedParser
//类说明：
//??	?? 获取RSS XML并解析的类;
 * RssFeedParser is an utility class for aquiring and parsing a RSS feed.
 * HttpConnection is used to fetch RSS feed and kXML is used on xml parsing.
 * 
//所在子系统：RssOwlMIDlet
//
//系统总描述:
	    我们提供的RSS无线阅读器J2ME版本[开源]是一个可以下载到手机(例如Nokia7610)或者其他无线手持设备(例如PocketPC)的应用程序，用来阅读存在于Internet中广泛的RSS新闻源。

	 子系统描述：
		RSS无线阅读器的功能列表：
	RSS Feed列表
		添加Rss Feed
		编辑Rss Feed
		删除Rss Feed
	读取Rss Feed新闻
		查看新闻摘要
		重新读取Rss Feed新闻
////////////////////////////////////////////////////////////////////*/

package com.zemo.model;

import javax.microedition.io.*;
import javax.microedition.lcdui.Image;
import javax.microedition.lcdui.List;

import java.util.*;
import java.io.*;
import org.xmlpull.v1.*;
import org.kxml2.io.*;

import com.zemo.control.GUIController;
import com.zemo.view.RssFeedOpen;

/**
 * RssFeedParser is an utility class for aquiring and parsing a RSS feed.
 * HttpConnection is used to fetch RSS feed and kXML is used on xml parsing.
 */
/**********************************************************
//RssFeedParser
//
//Class Description:
 * RssFeedParser is an utility class for aquiring and parsing a RSS feed.
 * HttpConnection is used to fetch RSS feed and kXML is used on xml parsing.
**********************************************************/
public class RssFeedParser {
    
	private GUIController 	 controller;
    private RssFeed m_rssFeed;  // The RSS feed
    private XmlPullParser m_xmlParser = new KXmlParser(); // The Xml parser
	
	public RssFeedOpen openForm;
    
    /** Create new instance of RssDocument */
    public RssFeedParser(RssFeed rssFeed, GUIController control) {
        m_rssFeed = rssFeed;
		controller = control;
    }
    
    /** Return RSS feed */
    public RssFeed getRssFeed() {
        return m_rssFeed;
    }
    
	/**********************************************************
	//	 RssFeedParser::parseRssFeed
	//
	//	 Description:
	//	  send a GET request to web server
	//
	//	 Parameters:
	//	 Return Values:
	//   Remark:
	 * 		经过试验,我们千万不能加入"User-Agent"Header字段
	 * 
	**********************************************************/
    public boolean parseRssFeed()
    throws IOException, Exception {
		System.out.println("/** Enter parseRssFeed */");
        
		boolean bParseOk = false;
        HttpConnection hc = null;
        String response = "";
        try {
            /**
             * Open an HttpConnection with the Web server
             * The default request method is GET
             */
			String url = m_rssFeed.getUrl();
			System.out.println("/** Connect to:" + url);
            hc = (HttpConnection) Connector.open( url );
            hc.setRequestMethod(HttpConnection.GET);
            /** Some web servers requires these properties */
			
			/*
			 * 这博客堂/博客园两个站点对于我们的请求返回这样的错误信息：
			 * Bad Request (Invalid Header Name)
			 * 特此记录!
			 * 经过试验,我们千万不能加入"User-Agent"Header字段,虽然其他非.Text类型Blog支持我们的
			 * User-Agent,但是博客堂/博客园是不支持的!
			 */
            //hc.setRequestProperty("User-Agent", 
            //        "Profile/MIDP-1.0 Configuration/CLDC-1.0");
			
            hc.setRequestProperty("Content-Length", "0");
			hc.setRequestProperty("Accept-Language", "zh-cn");
			hc.setRequestProperty("Accept-Encoding", "gzip, deflate");
            hc.setRequestProperty("Connection", "close");            
			
            /** 
             * Get a DataInputStream from the HttpConnection 
             * and forward it to kXML parser
             */
			System.out.println("/** openInputStream to:" + url);
			bParseOk = parseRssFeedXml( hc.openInputStream() );
        } catch(Exception e) {
            throw new Exception("Error while parsing RSS data: " 
                    + e.toString());
        } finally {
            if (hc != null) hc.close();
        }
		
		return bParseOk;
    }

	/**********************************************************
	//	 RssFeedParser::parseRssFeedXml
	//
	//	 Description:
	 * Nasty RSS feed XML parser.
     * Seems to work with both RSS 1.0 and 2.0.
	//
	//	 Parameters:
	//	 Return Values:
	//   Remark:
	 * 		下面我们看看KXML如何做一个Pull语法分析程序。
	 		首先我们需要创建了一个XmlParser，并把它传到一个InputStream中。
	 		其次，我们需要跳过RSS根节点的“rss”之类的东西。
	 		下面，我们来寻找RSS中的第一个“item”节点，
	 		它代表这个RSS文档中确实包含了新闻条目。这是通过下面的循环做到的。
	 		parser.next()的含义是“Get next parsing event”，这样就可以遍历文档，
	 		如果找不到item节点，就抛出一个异常。
	 		
	 		确认有item节点后，我们来寻找RSS中代表每一个新闻的“item”节点下的三个节点“title”
	 		“link”“description”，这是通过下面的循环做到的。parser.next()的含义是
	 		“Call next() event if it is START_TAG or END_TAG otherwise throw an exception”，
	 		这样就可以遍历文档找全所有的新闻的主题、链接和摘要了。
	**********************************************************/
    public boolean parseRssFeedXml(InputStream is) 
            throws IOException, XmlPullParserException {
		
		System.out.println("Enter parseRssFeedXml");
		
        /** Initialize item collection */
        m_rssFeed.getItems().removeAllElements();
		//System.out.println("End removeAllElements");
        
        /** Initialize XML parser and parse RSS XML */
        KXmlParser  parser = new KXmlParser();
		//parser.setInput( new InputStreamReader(is));
		
		//boolean bHasXMLEntity = false;
		try
		{
			System.out.println("Begin setInput");
			//parser.setInput( is,"utf-8"); // 设置读取用UTF-8编码
			parser.setInput( is, null); // 设置null让KXmlParser自动检测该使用哪种编码
		}
		catch(org.xmlpull.v1.XmlPullParserException exc)
		{
			System.out.println("!-- 解析时发生异常: --!\nException:" + exc.getMessage());
			parser.setInput( is,"utf-8");
		}
		finally{
			System.out.println("End setInput");
		}
		
		////////////////////////////////////////////////
		/// 下面的代码用于寻找当前RSS文档是否以<?xml...开头
		/*byte[] srcBuf = new byte[2];
		int srcCount = is.read(srcBuf, 0, srcBuf.length);
		int nBufChar;
        if (srcCount <= 0)
			nBufChar = -1;
        else
			nBufChar = srcBuf[0];
		if (nBufChar == '<') {
			System.out.println("确实找到了<");
			nBufChar = srcBuf[1];
			if (nBufChar == '?')
			{
				System.out.println("确实找到了<?xml...");
				bHasXMLEntity = true;
			}
        }*/
		////////////////////////////////////////////////

        /** RSS item properties */
        String title = null;
        String description = null;
        String link = null;

		/*if(true == bHasXMLEntity)
		{
	        // 这个nextTag()是为了跳过"<?xml..."的,但是有许多RSS不规范,并没有生成<?xml...,在这种情况下
	        // ,往往会在这句话上失败,并报告说“org.xmlpull.v1.XmlPullParserException: PI must not start with xml”
	        parser.nextTag();
			System.out.println("执行nextTag跳过<?xml...");
		}*/

		parser.nextTag();
		System.out.println("执行nextTag");
		/** Various tags... Wait for the <item> tag */
        parser.require(parser.START_TAG, null, null);
		System.out.println("执行require START_TAG");
		
		/*
		 * 如果你看到“Error: Error while parsing RSS data: w: unresolved: (position:TEXT
		@14:224 in java.io.InputStreamReader@ea0ef881”的错误，那么是不是前面还输出了许多XML的节点名称，那么是否有“#==XML Node Name:html”这样的输出呢？
		如果有，这表明该Rss Feed返回的并不是xml，而是html文档。
		 */
        while(!"item".equals(parser.getName()) ){
			String strTagName = parser.getName();
			if(strTagName != null)
			{
				System.out.println("#==XML Node Name:" + strTagName);
				if( strTagName.toLowerCase().compareTo("html") == 0 )
				{
	                String sError = "这并不是Rss Feed，返回的是HTML文档!";
					Object[] args = {sError};    		
					controller.handleEvent(GUIController.EventID.EVENT_PARSE_RSS_ERROR,args);
					return false;
				}
			}
			//System.out.println("#==XML Node Text:" + parser.getText());
            /** Check if document doesn't include any item tags */
            if( parser.next() == parser.END_DOCUMENT )
			{
				String sError = "该Rss Feed没有发布任何文章!";
				Object[] args = {sError};    		
				controller.handleEvent(GUIController.EventID.EVENT_PARSE_RSS_ERROR,args);
				return false;
			}
        }

        /** Parse <item> tags */
        do {
            parser.require(parser.START_TAG, null, null);

            /** Initialize properties */
            title = "";
            description = "";
            link = "";

            /** One <item> tag handling*/
            while (parser.nextTag() != parser.END_TAG) {
                parser.require(parser.START_TAG, null, null);
                String name = parser.getName();
                String text = parser.nextText();

                /** Save item property values */
                if (name.equals("title"))
                    title = text;
                else if (name.equals("description"))
                    description = text;
                else if (name.equals("link"))
                    link = text;

                parser.require(parser.END_TAG, null, name);
            }
            
            /** Debugging information */
            System.out.println ("Title:       " + title);
            //System.out.println ("Link:        " + link);
            //System.out.println ("Description: " + description);

            /** Create new RSS item and add it do RSS document's item
             *  collection
             */
            RssItem rssItem = new RssItem(title, link, description);
            m_rssFeed.getItems().addElement( rssItem );
			
			openForm.appendRssItem(title);
			
            parser.nextTag();
            
        } while("item".equals(parser.getName()));
		
		parser = null;
		
		return true;
    }        
}
